package nc.tb.cube.fmldim;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;

import nc.tb.busilogic.AnalyTemplateCol;
import nc.tb.cube.vo.CdViewFmlDimVO;
import nc.tb.dim.DimDef;
import nc.tb.dim.data.DimManager;
import nc.tb.pub.IDimPkConst;
import nc.tb.pub.util.NtbLogger;
import nc.vo.pub.BusinessException;

public class FmlDimGenerator {
	
	public static IFmlDim[] convertVOs2BOs(CdViewFmlDimVO[] vos) throws BusinessException {
		if (vos == null || vos.length == 0)
			return new IFmlDim[0];
			//throw new BusinessException("FmlDimGenerator.convertVOs2BOs() err: input is empty");
		IFmlDim[] bos = new IFmlDim[vos.length];
		for (int i=0; i<bos.length; i++)
			bos[i] = convertByVO(vos[i]);
		return bos;
	}
	
	public static CdViewFmlDimVO[] convertBOs2VOs(IFmlDim[] bos) throws BusinessException {
		if (bos == null || bos.length == 0)
			return null;
			//throw new BusinessException("FmlDimGenerator.convertBOs2VOs() err: input is empty");
		CdViewFmlDimVO[] vos = new CdViewFmlDimVO[bos.length];
		for (int i=0; i<bos.length; i++) {
			if (bos[i] == null)
				throw new BusinessException("FmlDimGenerator.convertBOs2VOs() err: input["+i+"] is null");
			vos[i] = bos[i].getVO();
		}
		return vos;
	}

	public static IFmlDim convertByVO(CdViewFmlDimVO m_vo) throws BusinessException {
		if (m_vo == null)
			throw new BusinessException("FmlDimGenerator.convertByVO() err: input CdViewFmlDimVO is null");
		if (m_vo.getFml_type() == null)
			throw new BusinessException("FmlDimGenerator.convertByVO() err: input CdViewFmlDimVO "+FmlDimConst.FML_DIM_PROPERTYS[FmlDimConst.FML_DIM_PROPERTY_FORMULA_TYPE]+" is null");

		try {
			IFmlDim bo = (IFmlDim)getClassByType(m_vo.getFml_type().intValue()).newInstance();
			bo.setVO(m_vo);
			return bo;
		}
		catch(InstantiationException e1) {
			NtbLogger.printException(e1);
			throw new IllegalFmlDimException(FmlDimConst.FML_DIM_PROPERTY_FORMULA_TYPE, m_vo.getFml_type().toString(), e1.getMessage());
		}
		catch(IllegalAccessException e2) {
			NtbLogger.printException(e2);
			throw new IllegalFmlDimException(FmlDimConst.FML_DIM_PROPERTY_FORMULA_TYPE, m_vo.getFml_type().toString(), e2.getMessage());
		}
	}
	
	public static IFmlDim createByFmlType(int fml_type) throws IllegalFmlDimException {
		try {
			IFmlDim bo = (IFmlDim)getClassByType(fml_type).newInstance();
			bo.setVO(createCdViewFmlDimVOByType(fml_type));
			return bo;
		}
		catch(InstantiationException e1) {
			NtbLogger.printException(e1);
			throw new IllegalFmlDimException(FmlDimConst.FML_DIM_PROPERTY_FORMULA_TYPE, ""+fml_type, e1.getMessage());
		}
		catch(IllegalAccessException e2) {
			NtbLogger.printException(e2);
			throw new IllegalFmlDimException(FmlDimConst.FML_DIM_PROPERTY_FORMULA_TYPE, ""+fml_type, e2.getMessage());
		}
	}
	
	private static CdViewFmlDimVO createCdViewFmlDimVOByType(int fml_type) {
		CdViewFmlDimVO vo = new CdViewFmlDimVO();
		vo.setFml_type(fml_type);
		vo.setChanged(false);
		return vo;
	}
	
	private static Class getClassByType(int fml_type) throws IllegalFmlDimException {
		switch(fml_type) {
			case FmlDimConst.FML_DIM_FORMULA_TYPE_GETVALUEBYDIM :
				return FdGetValueByDim.class;
			case FmlDimConst.FML_DIM_FORMULA_TYPE_SUM :
				return FdSum.class;
			case FmlDimConst.FML_DIM_FORMULA_TYPE_SUM_MUTI :
				return FdMutiSum.class;
			case FmlDimConst.FML_DIM_FORMULA_TYPE_OPERATE_CYE :
			case FmlDimConst.FML_DIM_FORMULA_TYPE_OPERATE_CYL :
			case FmlDimConst.FML_DIM_FORMULA_TYPE_OPERATE_WCL :
				return FdOperateCY.class;
			case FmlDimConst.FML_DIM_FORMULA_TYPE_NULL :
				return FdNull.class;
			default:
				throw new IllegalFmlDimException(FmlDimConst.FML_DIM_PROPERTY_FORMULA_TYPE, ""+fml_type);
		}
	}
	
	public static void buildFmlDimsMap(IFmlDim[] fds, HashMap<String,IFmlDim[]> hmViewCell2Fd, HashMap<String,IFmlDim[]> hmDimDef2Fd) {
		if (fds == null)
			return;
		HashMap<String,ArrayList<IFmlDim>> tmp1 = new HashMap<String,ArrayList<IFmlDim>>();
		HashMap<String,ArrayList<IFmlDim>> tmp2 = new HashMap<String,ArrayList<IFmlDim>>();
		for (int i=0; i<fds.length; i++) {
			int pType = fds[i].getParent_type();
			if (pType == FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF) {
				String key = fds[i].getPk_parent();
				ArrayList<IFmlDim> value = tmp1.get(key);
				if (value == null) {
					value = new ArrayList<IFmlDim>();
					tmp1.put(key, value);
				}
				value.add(fds[i]);
			}
			else if (pType == FmlDimConst.FML_DIM_PARENT_TYPE_VIEWCELL) {
				String key = fds[i].getPk_parent();
				ArrayList<IFmlDim> value = tmp2.get(key);
				if (value == null) {
					value = new ArrayList<IFmlDim>();
					tmp2.put(key, value);
				}
				value.add(fds[i]);
			}
		}
		for (Iterator<String> it = tmp1.keySet().iterator(); it.hasNext(); ) {
			String key = it.next();
			ArrayList<IFmlDim> value = tmp1.get(key);
			if (value != null && !value.isEmpty()) {
				IFmlDim[] v = value.toArray(new IFmlDim[0]);
				Arrays.sort(v, new FmlDimComparator());
				hmDimDef2Fd.put(key, v);
			}
		}
		for (Iterator<String> it = tmp2.keySet().iterator(); it.hasNext(); ) {
			String key = it.next();
			ArrayList<IFmlDim> value = tmp2.get(key);
			if (value != null && !value.isEmpty()) {
				IFmlDim[] v = value.toArray(new IFmlDim[0]);
				Arrays.sort(v, new FmlDimComparator());
				hmViewCell2Fd.put(key, v);
			}
		}
	}
	
	public static IFmlDimGroup getFmlDimGroupNewInstance() {
		return new AbstractFmlDimGroup();
	}
	
	public static IFmlDimGroup getFmlDimGroup(IFmlDim[] fds) {
		IFmlDimGroup fg = new AbstractFmlDimGroup();
		boolean b = ((AbstractFmlDimGroup)fg).isAutoCombin;
		fg.setIsAutoCombin(false);
		if (fds != null)
			fg.addArray(new ArrayList<IFmlDim>(Arrays.asList(fds)));
		fg.setIsAutoCombin(b);
		return fg;
	}
	
	public static IFmlDim cloneAll(IFmlDim fd) throws BusinessException {
		if (fd == null)		return null;
		return convertByVO((CdViewFmlDimVO)fd.getVO().clone());
	}
	
	public static IFmlDim cloneNew(IFmlDim fd) throws IllegalFmlDimException {
		return cloneNewByType(fd, fd.getFml_type());
	}
	
	public static IFmlDim cloneNewByType(IFmlDim fd, int fml_type) throws IllegalFmlDimException {
		if (fd == null)		return null;
		checkFml_typeCanbeConvert(fd.getFml_type(), fml_type);
		IFmlDim result = createByFmlType(fml_type);
		result.setPk_cube(fd.getPk_cube());
		result.setPk_cubeview(fd.getPk_cubeview());
		result.setParent(fd.getParent_type(), fd.getPk_parent());
		result.setIndex(fd.getIndex());
		result.setObjname(fd.getObjname());
		result.setPk_dimdef(fd.getPk_dimdef());
		result.setContent(fd.getContent());
		result.setCommondimvectorStr(fd.getCommondimvectorStr());
		result.setArguments(fd.getArguments());
		return result;
	}
	
	private static void checkFml_typeCanbeConvert(int type1, int type2) throws IllegalFmlDimException {
		if (type1 == type2)		return;
		try {
			String s1 = Integer.toString(type1);
			String s2 = Integer.toString(type2);
			if (s1.charAt(0) != s2.charAt(0))
				throw new IllegalFmlDimException(FmlDimConst.FML_DIM_PROPERTY_FORMULA_TYPE, type1+","+type2);
		}
		catch (IllegalFmlDimException ie) {
			throw ie;
		}
		catch (Exception e) {
			NtbLogger.printException(e);
			throw new IllegalFmlDimException(FmlDimConst.FML_DIM_PROPERTY_FORMULA_TYPE, type1+","+type2);
		}
	}
	
	public static IFmlDimGroup combinFmlDimGroups(IFmlDimGroup[] fgs) {
		if (fgs == null || fgs.length == 0)		return null;
		IFmlDimGroup result = getFmlDimGroupNewInstance();
		result.setIsAutoCombin(false);
		for (int i=0; i<fgs.length; i++)
			result.addArray(fgs[i].getFmlDims());
		return result;
	}
	
	public static IFmlDim createDefaultDimMatchFmlDim(DimDef dd) {
		try {
			IFmlDim result = createByFmlType(FmlDimConst.FML_DIM_FORMULA_TYPE_GETVALUEBYDIM);
			result.setGroup_id(0);
			result.setIndex(0);
			result.setArguments("lvl=lower;");
			if (dd != null) {
				result.setParent(FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF, dd.getPrimaryKey());
				result.setPk_dimdef(dd.getPrimaryKey());
			}
			return result;
		}
		catch (IllegalFmlDimException ie) {
			return null;
		}
	}
	
	public static IFmlDim createDefaultDimMatchLastYearFmlDim(DimDef dd) {
		try {
			IFmlDim result = createByFmlType(FmlDimConst.FML_DIM_FORMULA_TYPE_GETVALUEBYDIM);
			result.setGroup_id(0);
			result.setIndex(0);
			result.setArguments("year=N-1;lvl=lower;");
			if (dd != null) {
				result.setParent(FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF, dd.getPrimaryKey());
				result.setPk_dimdef(dd.getPrimaryKey());
			}
			return result;
		}
		catch (IllegalFmlDimException ie) {
			return null;
		}
	}
	
	public static IFmlDim createDefaultSumFmlDim(DimDef dd) {
		try {
			IFmlDim result = createByFmlType(FmlDimConst.FML_DIM_FORMULA_TYPE_SUM);
			result.setGroup_id(0);
			result.setIndex(0);
			result.setContent("dimM=all;");
			result.setArguments("enuC=N;type=dimM;lvl=after;");
			if (dd != null) {
				result.setParent(FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF, dd.getPrimaryKey());
				result.setPk_dimdef(dd.getPrimaryKey());
			}
			return result;
		}
		catch (IllegalFmlDimException ie) {
			return null;
		}
	}
	
	public static IFmlDim createDefaultSumYearFmlDim(DimDef dd, String pk_timeDim) {
		try {
			IFmlDim result = createByFmlType(FmlDimConst.FML_DIM_FORMULA_TYPE_SUM);
			result.setGroup_id(0);
			result.setIndex(0);
			result.setContent("time=1~N;");
			result.setArguments("year=N-1;enuC=Y;type=time;lvl=lower;");
			result.setPk_dimdef(pk_timeDim);
			if (dd != null) {
				result.setParent(FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF, dd.getPrimaryKey());
			}
			return result;
		}
		catch (IllegalFmlDimException ie) {
			return null;
		}
	}
	
	public static IFmlDim[] createDefaultCYFmlDim(DimDef dd) {
		IFmlDim[] result = new IFmlDim[4];
		try {
			result[0] = createByFmlType(FmlDimConst.FML_DIM_FORMULA_TYPE_GETVALUEBYDIM);
			result[0].setCommondimvectorStr(IDimPkConst.PKMVTYPE+"="+IDimPkConst.PLAN_VALUE+";");
			result[0].setGroup_id(0);
			result[0].setIndex(0);
			result[0].setArguments("para=Y;lvl=lower;");
			result[1] = createByFmlType(FmlDimConst.FML_DIM_FORMULA_TYPE_GETVALUEBYDIM);
			result[1].setCommondimvectorStr(IDimPkConst.PKMVTYPE+"="+IDimPkConst.REAL_VALUE+";");
			result[1].setGroup_id(0);
			result[1].setIndex(1);
			result[1].setArguments("para=Y;lvl=lower;");
			result[2] = createByFmlType(FmlDimConst.FML_DIM_FORMULA_TYPE_OPERATE_CYE);
			result[2].setPk_dimdef(IDimPkConst.PKMVTYPE);
			result[2].setContent("dimM="+IDimPkConst.REAL_VALUE+","+IDimPkConst.PLAN_VALUE+";");
			result[2].setGroup_id(0);
			result[2].setIndex(2);
			result[2].setArguments("type=dimM;lvl=lower;");
			result[3] = createByFmlType(FmlDimConst.FML_DIM_FORMULA_TYPE_OPERATE_CYL);
			result[3].setPk_dimdef(IDimPkConst.PKMVTYPE);
			result[3].setContent("dimM="+IDimPkConst.REAL_VALUE+","+IDimPkConst.PLAN_VALUE+";");
			result[3].setGroup_id(0);
			result[3].setIndex(3);
			result[3].setArguments("type=dimM;lvl=lower;");
			if (dd != null) {
				result[0].setParent(FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF, dd.getPrimaryKey());
				result[1].setParent(FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF, dd.getPrimaryKey());
				result[2].setParent(FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF, dd.getPrimaryKey());
				result[3].setParent(FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF, dd.getPrimaryKey());
			}
		}
		catch (IllegalFmlDimException ie) {
			return null;
		}
		return result;
	}
	public static IFmlDim createExtendFmlDim(AnalyTemplateCol aCol,DimDef dd, DimDef timeDim,
			boolean isTemplate4Row) {
		IFmlDim result = null;
		try {
			result = createByFmlType(aCol.getFormulaType());
			result.setObjname(aCol.getName());
			result.setCommondimvectorStr(aCol.getCommonDimvector());
			result.setGroup_id(aCol.getGroupID());
//			result.setIndex(aCol.getIdx());
			result.setArguments(aCol.getArguments());
			String strParam = aCol.getDimDef();
			if(strParam != null && strParam.trim().length() > 0){
				try {
					String[] ary = strParam.split(" ");
					DimDef ddCol = DimManager.getDimDefByCode(ary[0]);
					if(ddCol != null)
						result.setPk_dimdef(ddCol.getPrimaryKey());
				} catch (Exception e) {
					// TODO: handle exception
					NtbLogger.printException(e);
				}
			}
			strParam = aCol.getContent();
			if(strParam != null && strParam.trim().length() > 0){
				result.setContent(strParam);
			}
			strParam = aCol.getValueType();
			if(strParam != null && strParam.trim().length() > 0){
				result.getArgument(FmlDimConst.ARG_MATCH_TYPE);
				result.setArgument(FmlDimConst.ARG_MATCH_TYPE,strParam);
			}
			if (dd != null) {
				result.setParent(FmlDimConst.FML_DIM_PARENT_TYPE_DIMDEF, dd.getPrimaryKey());
			}
			if(aCol.isPercent()){
				result.getArgument(FmlDimConst.ARG_PER);
				result.setArgument(FmlDimConst.ARG_PER, "Y");
			}
		}
		catch (Exception ie) {
			NtbLogger.printException(ie);
			return null;
		}
		return result;
	}
}
